﻿using System;
using System.Drawing;
using System.IO;
using System.Net;
using System.Threading;
using System.Windows.Forms;
using System.ComponentModel;

namespace Raider.WinForms.Actions.Demo
{
    public partial class TestForm : Form
    {
        public TestForm()
        {
            InitializeComponent();

            // Create custom action and link it with the button and 
            // menu item.
            var myAction = new CustomAction();
            actionManager.SetAction(myActionButton, myAction);
            actionManager.SetAction(myActionMenuItem, myAction);
        }

        private void TestFormLoad(object sender, EventArgs e)
        {
            // Use system font.
            Font = SystemFonts.MessageBoxFont;

            // Bind comboBox with actions' collection.
            comboBox.DataSource = actionManager.Actions;
        }

        // Usually you don't need such checking methods. I wrote them because 
        // in this app users can set wrong properties at run-time.
        #region Thread Check

        private bool CheckExecuteThread(object sender)
        {
            if (InvokeRequired)
            {
                MessageBox.Show(sender + " can only be executed on the main (UI) thread.\n" + 
                    "AsyncExecute will be set to false.\n" +
                    "Please repeat your last action.",
                    Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);

                var action = (AsyncAction)sender;
                action.AsyncExecute = false;
            }

            return !InvokeRequired;
        }

        private bool CheckUpdateThread(object sender)
        {
            if (InvokeRequired)
            {
                MessageBox.Show(sender + " can only be updated on the main (UI) thread.\n" + 
                    "AsyncUpdate will be set to false.",
                    Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);

                var action = (AsyncAction)sender;
                action.AsyncUpdate = false;
            }

            return !InvokeRequired;
        }

        #endregion

        private void EnableButtonClick(object sender, EventArgs e)
        {
            // Enable/disable ActionManager. Disabled ActionManager does not 
            // update it's actions automatically, and does not handle any events
            // from the client controls.
            actionManager.Enabled = enableButton.Checked;
            enableButton.Text = actionManager.Enabled ? "ActionManager Enabled" : "ActionManager Disabled";
        }

        private void ComboBoxSelectedIndexChanged(object sender, EventArgs e)
        {
            propertyGrid.SelectedObject = comboBox.SelectedItem;
        }

        private void ComboBoxFormat(object sender, ListControlConvertEventArgs e)
        {
            // Remove ampersands (aka mnemonics).
            if (e.Value != null) e.Value = e.Value.ToString().Replace("&", "");
        }

        private void OnNewActionExecute(object sender, ExecuteEventArgs args)
        {
            if (!CheckExecuteThread(sender)) return;

            richTextBox.Clear();
            richTextBox.Focus();
        }

        // This handler is invoked when user clicks OK in the Open dialog.
        private void OnOpenActionAccept(object sender, EventArgs args)
        {
            if (!CheckExecuteThread(sender)) return;

            var ext = Path.GetExtension(openAction.Dialog.FileName);
            var type = string.Equals(ext, ".rtf", StringComparison.OrdinalIgnoreCase)
                ? RichTextBoxStreamType.RichText
                : RichTextBoxStreamType.PlainText;

            richTextBox.LoadFile(openAction.Dialog.FileName, type);
        }

        // This handler is invoked when user clicks OK in the Save dialog.
        private void OnSaveActionAccept(object sender, EventArgs args)
        {
            if (!CheckExecuteThread(sender)) return;

            richTextBox.SaveFile(saveAction.Dialog.FileName);
        }

        // This handler is invoked on UI thread BEFORE AsyncActionExecute.
        private void AsyncActionExecuting(object sender, ExecutingEventArgs args)
        {
            asyncAction.Enabled = false;
            asyncAction.Title = "Performing background operation...";
            args.Argument = "http://thewalter.net/stef/software/rtfx/sample.rtf";
        }

        // This handler is invoked asynchronously.
        // You should handle exceptions in async event handlers by yourself. In this example,
        // we just save catched exception to ExecuteEventArgs.Result property (to handle it later).
        private void AsyncActionExecute(object sender, ExecuteEventArgs args)
        {
            try
            {
                using (var client = new WebClient())
                {
                    var uri = (string)args.Argument;
                    var byteStream = new MemoryStream(client.DownloadData(uri));
                    args.Result = byteStream;
                }

                // Reduce flicker (DownloadData may execute too fast).
                Thread.Sleep(1000);
            }
            catch (Exception ex)
            {
                args.Result = ex;
            }
        }

        // This handler is invoked on UI thread AFTER AsyncActionExecute.
        private void AsyncActionExecuted(object sender, ExecutedEventArgs args)
        {
            if (args.Result is Exception)
            {
                MessageBox.Show(args.Result.ToString(),
                    Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
            else
            {
                using (var stream = (Stream)args.Result)
                {
                    richTextBox.LoadFile(stream, RichTextBoxStreamType.RichText);
                }
            }

            asyncAction.Title = "&Background Action Example";
            asyncAction.Enabled = true;
        }

        // Update handlers are invoked automatically when application is in the idle state.
        // Ususally they are used to set appropriate Enabled state of the action.
        private void SelectFontActionUpdate(object sender, UpdateEventArgs e)
        {
            if (!CheckUpdateThread(sender)) return;

            selectFontAction.Enabled = richTextBox.SelectionLength > 0;
        }

        // This handler is invoked BEFORE SelectFontActionAccept.
        private void SelectFontActionExecuting(object sender, ExecutingEventArgs args)
        {
            selectFontAction.Dialog.Font = richTextBox.SelectionFont;
        }

        // This handler is invoked AFTER SelectFontActionExecuting, but only
        // if user clicked OK in the dialog.
        private void SelectFontActionAccept(object sender, EventArgs e)
        {
            if (!CheckExecuteThread(sender)) return;

            richTextBox.SelectionFont = selectFontAction.Dialog.Font;
        }

        private void SelectColorActionUpdate(object sender, UpdateEventArgs e)
        {
            if (!CheckUpdateThread(sender)) return;

            selectColorAction.Enabled = richTextBox.SelectionLength > 0;
        }

        private void SelectColorActionExecuting(object sender, ExecutingEventArgs args)
        {
            selectColorAction.Dialog.Color = richTextBox.SelectionColor;
        }

        private void SelectColorActionAccept(object sender, EventArgs e)
        {
            if (!CheckExecuteThread(sender)) return;

            richTextBox.SelectionColor = selectColorAction.Dialog.Color;
        }
    }
}
